package com.keba.basic.encrypt.filter;

import com.keba.basic.encrypt.codec.SecurityProcessor;
import com.keba.basic.utils.ArgumentAssert;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Objects;

/**
 * @author twg
 * @description web请求过滤器
 * @date 2024/05/20 14:38
 **/
@Slf4j
@AllArgsConstructor
public class SecurityRequestFilter implements Filter {

    private final SecurityProcessor securityProcessor;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if (Objects.isNull(servletRequest.getContentType()) || MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(servletRequest.getContentType())) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String encrypt = httpServletRequest.getHeader("Content-Encrypt");
        if (StrUtil.isBlank(encrypt) || "false".equals(encrypt)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        String body = servletRequest.getReader().lines().reduce("", (p, l) -> p + l);
        if (StrUtil.isBlank(body)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        ArgumentAssert.isTrue(JSONUtil.isTypeJSON(body), "非JSON格式，请核对后再试");
        JSONObject jsonObject = JSONUtil.parseObj(body);
        String data = jsonObject.getStr("data");
        body = StrUtil.str(securityProcessor.decrypt(data), CharsetUtil.CHARSET_UTF_8);
        filterChain.doFilter(new BodyRequestWrapper((HttpServletRequest) servletRequest, body), servletResponse);
    }

    private static class BodyRequestWrapper extends HttpServletRequestWrapper {

        private final String body;

        public BodyRequestWrapper(HttpServletRequest request, String body) {
            super(request);
            this.body = body;
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes(CharsetUtil.CHARSET_UTF_8));
            return new ServletInputStream() {
                @Override
                public boolean isFinished() {
                    return false;
                }

                @Override
                public boolean isReady() {
                    return false;
                }

                @Override
                public void setReadListener(ReadListener readListener) {

                }

                @Override
                public int read() throws IOException {
                    return byteArrayInputStream.read();
                }
            };
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return IoUtil.getReader(this.getInputStream(), CharsetUtil.CHARSET_UTF_8);
        }
    }
}
